#include "UdevFilesystem.h"
#include <jimix/File.h>
#include <jimix/ProcessManager.h>
#include <jimix/ResourceManager.h>
#include <jimix/resource.h>
#include <jimix/MonitorDriver.h>

#include <string.h>
#include <stdio.h>

u32int devnull;
extern u32int _process;

int UdevFilesystem::nullRead(int impl, u32int offset, u32int size, u8int *buffer)
{
  memset(buffer, 0, size);
  return size;
}

int UdevFilesystem::nullWrite(int impl, u32int offset, u32int size, u8int *buffer)
{
  return size;
}

int UdevFilesystem::getItem(int impl, char *c, u32int f)
{
  // Here we hardcode support for /dev/tty, which should refer to the process'
  // controlling TTY.
  if (!strcmp(c, "tty"))
  {
    u32int sender = callResource(_process, Process_IF::getMessageSender);
    u32int processManager = requestResource("ProcessManager");
    u32int senderProcess = callResource(processManager, ProcessManager_IF::getProcess, sender);
    u32int ctty = callResource(senderProcess, Process_IF::getCtty);
    return (ctty==0)?-1:ctty;
  }
  return f;
}

UdevFilesystem::UdevFilesystem()
{
  u32int resourceManager = requestResource("ResourceManager");
  char *str = (char*)callResource(resourceManager, ResourceManager_IF::share, "devfs", 6);
  resource = createResource((Callable*)this, str);
  addFunction(resource, (Resource::Call4)&UdevFilesystem::nullRead, FILE_READ);
  addFunction(resource, (Resource::Call4)&UdevFilesystem::nullWrite, FILE_WRITE);
  addFunction(resource, (Resource::Call3)&UdevFilesystem::getItem, DIR_GETENTRY);
  addFunction(resource, (Resource::Call4)&UdevFilesystem::makedev, UdevFilesystem_IF::makedev);
  

  filesystem = callResource(resourceManager, ResourceManager_IF::mkfs);

  // set up the root directory.
  u32int root = callResource(filesystem, Filesystem_IF::mknod, eFileType_Directory, NULL, resource, 0);
  
  callResource(filesystem, Filesystem_IF::setRoot, root);
  
  // set up /dev/null/
  devnull = callResource(filesystem, Filesystem_IF::mknod, eFileType_CharDevice, "null", resource, 0);
}


UdevFilesystem::~UdevFilesystem()
{
}

int UdevFilesystem::makedev(char *name, bool isBlock, u32int number, u32int ownerResource)
{
  int len = strlen(name);
  u16int major = (u16int)(number>>16);
  u16int minor = (u16int)(number&0x0000FFFF);

  if (major != (u16int)-1)
  {
    len++;
  }
  if (minor != (u16int)-1)
  {
    len++;
  }
  char *localname = new char[len+1];
  strcpy(localname, name);
  int idx = strlen(name);
  if (major != (u16int)-1)
  {
    localname[idx++] = 'a'+(char)major;
  }
  if (minor != (u16int)-1)
  {
    localname[idx++] = '0'+(char)minor;
  }
  localname[idx] = '\0';
  
  u32int dev = callResource(filesystem, Filesystem_IF::mknod,
                            (isBlock)?eFileType_BlockDevice:eFileType_CharDevice,
                            localname, ownerResource, minor /* implDefined */);
  return 1;
}
